/*******************************************************************************
 ** 
 ** This file is part of cmemtrac
 ** (C) 2011 Kevin Druelle 
 **
 ** Cmemtrac is free software: you can redistribute it and/or modify
 ** it under the terms of the GNU Lesser General Public License as published by
 ** the Free Software Foundation, either version 3 of the License, or
 ** (at your option) any later version.
 ** 
 ** Cmemtrac is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 ** 
 ** You should have received a copy of the GNU General Public License
 ** along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 ** 
 ******************************************************************************/



#include <stdlib.h>

#include "clist.h"

#define CLIST_MAGIC_NUMBER 0xA7B9C3D1

struct clist_node_st{
	void 				* pData;
	struct clist_node_st 		* next;
	struct clist_node_st 		* previous;
};

struct clist_st{
	size_t				size;
	struct clist_node_st 		* first;
	struct clist_node_st 		* last;
	unsigned long 			magic;
};

int clist_init(clist_t * list){
    (*list) = malloc(sizeof(struct clist_st));
    (*list)->size = 0;
    (*list)->first = NULL;
    (*list)->last = NULL;
    (*list)->magic = CLIST_MAGIC_NUMBER;
    return 0;
}

int clist_isEmpty(clist_t list){
    return ((list->size == 0) ? 1 : 0);
}

size_t clist_getSize(clist_t list){
    return list->size;
}


void * clist_front(clist_t list){
    if(list == NULL){
        return NULL;
    }
    if(list->first != NULL)
        return list->first->pData;
    return NULL;
}
void * clist_back(clist_t list){
    if(list == NULL){
        return NULL;
    }
    if(list->last != NULL)
        return list->last->pData;
    return NULL;
}


int clist_pushFront(clist_t * list, void * pData){
    clist_node_t node;
    if((*list) == NULL){
        return NULL;
    }
    node = malloc(sizeof(struct clist_node_st));
    node->next = (*list)->first;
    node->previous = NULL;
    node->pData = pData;
    if((*list)->size == 0){
        (*list)->last = node;
        (*list)->first = node;
    }else{
        (*list)->first->previous = node;
        (*list)->first = node;
    }
    (*list)->size++;
    return 0;
}
int clist_pushBack(clist_t * list, void * pData){
    clist_node_t node;
    if((*list) == NULL){
        printf("NULL");
        return 1;
    }
    node = malloc(sizeof(struct clist_node_st));
    node->next = NULL;
    node->previous = (*list)->last;
    node->pData = pData;
    if((*list)->size == 0){
        (*list)->last = node;
        (*list)->first = node;
    }else{
        (*list)->last->next = node;
        (*list)->last = node;
    }
    (*list)->size++;
    return 0;
}

void * clist_popFront(clist_t * list){
    clist_node_t node;
    void * pData;
    if((*list)->size == 0){
        return NULL;
    }
    node = (*list)->first;
    (*list)->first = node->next;
    if((*list)->first != NULL)
        (*list)->first->previous = NULL;
    pData = node->pData;
    free(node);
    (*list)->size--;
    return pData;
}
void * clist_popBack(clist_t * list){
    clist_node_t node;
    void * pData;
    if((*list)->size == 0){
        return NULL;
    }
    node = (*list)->last;
    (*list)->last = node->previous;
    if((*list)->last != NULL)
        (*list)->last->next = NULL;
    pData = node->pData;
    free(node);
    (*list)->size--;
    return pData;
}

void clist_remove(clist_t * list, void * pData){
    clist_node_t node;
    if((*list)->size == 0){
        return;
    }
    node = (*list)->first;
    while(node != NULL){
        if(node->pData == pData){
            if(node->previous == NULL){ // the first element
                (*list)->first = node->next;
                if((*list)->first != NULL){
                    (*list)->first->previous = NULL;
                }
            }else if(node->next == NULL){ // the last element
                (*list)->last = node->previous;
                if((*list)->last != NULL){
                    (*list)->last->next = NULL;
                }
            }else{ // the element is within the list
                node->next->previous = node->previous;
                node->previous->next = node ->next;
            }
            free(node);
            (*list)->size--;
            break;
        }
        node = node->next;
    }
}



